import io
import logging
import os.path

from django.contrib.auth.models import User
from django.http import HttpResponse
from django.shortcuts import render

# Create your views here.
from django.views import View
from django_redis import get_redis_connection
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.status import HTTP_400_BAD_REQUEST, HTTP_500_INTERNAL_SERVER_ERROR
from rest_framework.viewsets import ModelViewSet, GenericViewSet, ReadOnlyModelViewSet
from rest_framework_extensions.cache.mixins import CacheResponseMixin
from rest_framework_simplejwt.views import TokenObtainPairView

from DrfStudy_33.settings import BASE_DIR, MEDIA_ROOT
from config.dbs.redisConfig import KEY_TEMPLATE, EXPIRE_TIME
from users.models import UserDetail, Area, Address
from users.serializer import UserSerializer, MyTokenObtainPairSerializer, UserDetailSerializer, \
    UpdatePasswordSerializer, AreaSerializer, ParentAreaSerializer, AddressSerializer
from utils.verifyUtil import ImageVerify


class ImageVerifyView(View):
    def get(self, request, func, uuid):
        # 生成验证码对象
        imageVerify = ImageVerify()
        # 获取图片和验证码答案
        img, code = imageVerify.verify_code()
        # 生成文件流对象  图片字节流
        img_bytes = io.BytesIO()
        # save方法来保存这个文件流对象
        img.save(img_bytes, format="PNG")
        # getvalue获取到图片的数据 响应给到客户端
        img_bytes = img_bytes.getvalue()

        # 把答案保存到redis数据库
        # 链接数据库 alias获取配置文件里面的redis配置
        cache = get_redis_connection(alias='verify_codes')
        # redis set 添加一个键值对
        # REGISTER_KEY_TEMPLATE % (func, uuid)键
        # func区分他登录的请求还是注册的请求
        # code 值（验证码答案）
        #  EXPIRE_TIME过期时间
        cache.set(KEY_TEMPLATE % (func, uuid), code, EXPIRE_TIME)
        return HttpResponse(img_bytes, content_type='image/png')


# 导入日志器
logger = logging.getLogger(__name__)


class UserViewSet(GenericViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

    # 重写了一个权限校验方法
    def get_permissions(self):
        # 判断当前路由调用的方法是不是now 如果是的话就添加登录权限校验
        # 你需要先登录才能才能查看到自己的信息
        if self.action in ["now", "info"]:
            permission_class = [IsAuthenticated]  # IsAuthenticated 登录权限类
        else:
            # 调用其他的方法不设置登录权限
            permission_class = []
        # 该方法需要返回一个列表，并且列表里面的每个元素应该是一个权限对象
        return [permission() for permission in permission_class]  # [权限对象]

    # 重新定义获取序列化器的方法
    def get_serializer_class(self):
        if self.action in ['info']:
            return UserDetailSerializer
        elif self.action in ["password"]:
            return UpdatePasswordSerializer
        else:
            return self.serializer_class

    # 重写创建的方法
    def create(self, request, *args, **kwargs):
        # 通过序列化器做反序列化的校验
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        #         得到用户传入的数据
        username = request.data.get("username")
        password = request.data.get("password")

        #         创建用户对象 做持久化的操作 保存到数据库里面
        user = User(username=username)
        user.set_password(password)
        user.save()

        # 通过序列化器进行序列化 返回创建的用户信息
        return Response(self.get_serializer(user).data)

    # 添加权限校验，获取用户信息的路由不会全部把信息展示出来
    # 继承的类不再是modelviewset 而是什么方法都是没有常规视图
    # 定义一个方法让我们自己可以查看到个人用户信息
    @action(methods=['get'], detail=False)
    def now(self, request):
        serializer = self.get_serializer(request.user)
        return Response(serializer.data)

    @action(methods=['put'], detail=False)
    def info(self, request):
        user = request.user
        # 限制 无论调用接口user_id传入的是多少，都需覆盖为当前登录的用户id
        request.POST._mutable = True
        request.data['user'] = user.id
        file = request.FILES.get('file')
        # 获取用户详情对象
        user_detail, created = UserDetail.objects.get_or_create(user=user)
        if file:
            # 判断文件的类型是否符合要求
            if file.content_type not in ('image/jpg', 'image/png'):
                print(123)
                return Response(status=HTTP_400_BAD_REQUEST)
            try:
                if user_detail.avatar:
                    old_avatar_path = os.path.join(MEDIA_ROOT, str(user_detail.avatar))
                    print(old_avatar_path)
                    # 判断图片路径是否存在
                    if os.path.exists(old_avatar_path):
                        # 删除旧头像图片
                        os.remove(old_avatar_path)
                user_detail.avatar = file
                user_detail.save()
            except Exception as e:
                logger.error("图片上传出现异常：%s" % e)
                return Response(status=HTTP_500_INTERNAL_SERVER_ERROR)
        #     partial=True允许部分更新
        user_detail_serializer = self.get_serializer(user.userdetail, data=request.data,
                                                     partial=True)
        user_detail_serializer.is_valid(raise_exception=True)
        user_detail_serializer.save()

        # 判断用户是否有详情数据
        # if hasattr(user, 'userdetail'):
        #     # 有则修改 数据对象 如果传入了实例对象 调用update方法
        #     # get_serializer 得到的序列化器是哪一个 用户序列化器
        #     # user.userdetail 是那张表的数据 用户详情表的数据
        #     user_detail_serializer = self.get_serializer(user.userdetail, data=request.data)
        # else:
        #     # 没有则创建 如果没有传入实例对象 调用的就是Create方法
        #     user_detail_serializer = self.get_serializer(data=request.data)
        # # 校验数据
        # user_detail_serializer.is_valid(raise_exception=True)
        # # 保存数据
        # user_detail_serializer.save()
        return Response(user_detail_serializer.data)

    @action(methods=['put'], detail=False)
    def password(self, request):
        user = request.user
        # 校验数据
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        password = request.data["password"]
        new_password = request.data["new_password"]
        if user.check_password(password):
            user.set_password(new_password)
            user.save()
            return Response({'msg': "修改成功"})
        else:
            return Response(status=HTTP_400_BAD_REQUEST)


class MyTokenObtainPairView(TokenObtainPairView):
    serializer_class = MyTokenObtainPairSerializer


# 继承缓存视图类 CacheResponseMixin
# 继承的第一顺序 只能在最前面不能放后面
class AreaViewSet(CacheResponseMixin, ReadOnlyModelViewSet):
    queryset = Area.objects.all()
    serializer_class = AreaSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        if self.action == 'list':
            return Area.objects.filter(parent=None)
        else:
            return self.queryset

    def get_serializer_class(self):
        if self.action == 'retrieve':
            return ParentAreaSerializer
        else:
            return self.serializer_class


class AddressViewSet(ModelViewSet):
    queryset = Address.objects.all()
    serializer_class = AddressSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        # 将登录用户的数据作为查询集
        # 通过管理器address_set得到用户的所有收货地址
        return self.request.user.address_set.all()

    def create(self, request, *args, **kwargs):
        max_count = 5
        #         判断如果获取的地址数大于5条则返回错误信息
        # 当地址数量为5 5》5结果为False 就可以创建第6条地址
        if self.get_queryset().count() > max_count:
            return Response(
                {"detail": f'收货地址数量超过{max_count}条上限'},
                status=HTTP_400_BAD_REQUEST
            )
        request.POST._mutable = True
        request.data['user'] = str(request.user.id)
        return ModelViewSet.create(self, request, *args, **kwargs)
